import { GetWelcomeCourseware, GetDirCourseware, GetGroupCourseware, GetSubGroupCourseware, GetTxtAdnImgContCourseware, GetSingleImgContCourseware, GetTwoImgAndTxtContCourseware, GetThreeImgAndTxtContCourseware, GetManyImgContCourseware, GetOnlyTextContCourseware, GetEndCourseware } from '@/mocks/template/create'
import type { Slide } from '@/types/slides'

type parentStackSchema = {
  name: string
  level: number
}

/**
 * 解析 Markdown 字符串
 * @param mdStr - 原始 Markdown 字符串
 * @returns 解析后的 Markdown 数据数组
 */
export function ParseMarkdown(mdStr: string): ClassifiedLine[] {
  const lines = mdStr.split('\n')
  const classifiedLines: ClassifiedLine[] = []
  const parentStack: parentStackSchema[] = []

  const createClassifiedLine = (type: PPTDataItemTypeEnum, name: string, parent: string): ClassifiedLine => ({
    type,
    name: name.trim(),
    content: [],
    parent,
  })

  const handleTitle = (line: string, level: number, isParagraph?: boolean) => {
    let name:string = ''
    if (isParagraph) {
      name = line.replace(/\*\*/g, '').trim()
    }
    else {
      name = line.slice(level + 1).trim()
    }
    const type = ['title', 'section', 'subsection', 'paragraph'][level - 1] as PPTDataItemTypeEnum

    let parent: string = ''

    while (parentStack.length > 0) {
      if (parentStack[parentStack.length - 1].level >= level) {
        parentStack.pop() // 没有大于当前标题级别的父级标题，清空栈
      }
      else {
        parent = parentStack[parentStack.length - 1].name
        break // 找到最近的父级标题
      }
    }
    
    const lineObject = createClassifiedLine(type, name, parent)
    classifiedLines.push(lineObject)
    parentStack.push({ name, level })
  }

  const handleContent = (line: string, category: PPTDdataItemContentCategoryEnum, trimStart = false) => {
    if (parentStack.length > 0) {
      const currentParent = parentStack[parentStack.length - 1]
      const item = classifiedLines.find((item) => item.name === currentParent.name)

      if (item) {
        item .content.push({
          category,
          content: trimStart ? line.trimStart() : line,
        })
      }

    }
  }

  lines.forEach((line) => {
    const trimmedLine = line.trim()

    if (trimmedLine.startsWith('# ')) {
      handleTitle(trimmedLine, 1)
    }
    else if (trimmedLine.startsWith('## ')) {
      handleTitle(trimmedLine, 2)
    }
    else if (trimmedLine.startsWith('### ')) {
      handleTitle(trimmedLine, 3)
    }
    else if (/^\*\*.*\*\*$/.test(trimmedLine)) {
      handleTitle(trimmedLine, 4, true)
    }
    else if (trimmedLine.startsWith('![')) {
      const mediaMatch = trimmedLine.match(/!\[(.*?)\]\((.*?)\)/)
      if (mediaMatch) handleContent(mediaMatch[2], 'media')
    }
    else if (trimmedLine.startsWith('|')) {
      handleContent(trimmedLine, 'table')
    }
    else if (/\$\$.*\$\$/.test(trimmedLine)) {
      handleContent(trimmedLine.replace(/\$\$/g, ''), 'latex')
    }
    else if (trimmedLine.startsWith('- ') || trimmedLine.startsWith('* ')) {
      handleContent(trimmedLine.slice(2), 'list-ul')
    }
    else if (/^\d+\. /.test(trimmedLine)) {
      handleContent(trimmedLine.replace(/^\d+\. /, ''), 'list-ol')
    }
    else if (trimmedLine) {
      handleContent(trimmedLine, 'text')
    }
  })

  return classifiedLines
}

/**
 * 根据解析后的 Markdown 数据生成 PPT 数据
 * @param mdData - 解析后的 Markdown 数据
 * @param tempId - 模板 ID
 * @returns 生成的 PPT 数据
 */
export async function GeneratePPT(mdData: ClassifiedLine[], tempId: string = 'blue'): Promise<Slide[]> {

  const dirArr: string[] = []
  const pptData: Slide[] = []

  let author: string = ''
  
  // 仅同源策略下可用
  if (window.parent) {
    const parentToken = window.localStorage.getItem(window.parent.$ROOT_LOCAL_NAME as string)
    if (parentToken) {
      try {
        const { loginUser } = JSON.parse(parentToken)
        if (loginUser) {
          author = (loginUser.userInfo || loginUser.user).nickname
        } 
      }
      catch (error) {
        author = 'Rollong'
      }
    }
  }
  
  const getContent = async (group: string, content: ClassifiedLineContSchema[]) => {
    if (content.length === 0) return

    const medias: string[] = []
    const texts: string[] = []
    const tables: string[] = []
    const latex: string[] = []
    const uls: string[] = []
    const ols: string[] = []

    content.forEach((item) => {
      if (item.category === 'media') {
        medias.push(item.content)
      }
      else if (item.category === 'text') {
        texts.push(item.content)
      }
      else if (item.category === 'table') {
        tables.push(item.content)
      }
      else if (item.category === 'latex') {
        latex.push(item.content)
      }
      else if (item.category === 'list-ul') {
        uls.push(item.content)
      }
      else if (item.category === 'list-ol') {
        ols.push(item.content)
      }
    })

    // 只有图片的正文
    if (medias.length > 0 && texts.length === 0 && uls.length === 0 && ols.length === 0) {
      if (medias.length === 1) {
        const singleImgContPPT = await GetSingleImgContCourseware(tempId, {group, img: medias[0]})
        pptData.push(singleImgContPPT as Slide)
      }
      else {
        const manyImgContPPT = await GetManyImgContCourseware(tempId, {group, img: medias})
        pptData.push(manyImgContPPT as Slide)
      }
    }

    // 只有文字的正文
    if (texts.length > 0 && medias.length === 0 && tables.length === 0 && latex.length === 0) {
      // 先将 uls 和 ols 合并到 texts 中
      if (uls.length > 0) {
        uls.forEach((ul) => {
          texts.push(ul)
        })
      }
      if (ols.length > 0) {
        ols.forEach((ol) => {
          texts.push(ol)
        })
      }

      const onlyTextContPPT = await GetOnlyTextContCourseware(tempId, {group, txt: texts})
      pptData.push(onlyTextContPPT as Slide)
    }

    if (texts.length === 0 && uls.length > 0) {
      const onlyTextContPPT = await GetOnlyTextContCourseware(tempId, {group, txt: uls})
      pptData.push(onlyTextContPPT as Slide)
    }

    if (texts.length === 0 && ols.length > 0) {
      const onlyTextContPPT = await GetOnlyTextContCourseware(tempId, {group, txt: ols})
      pptData.push(onlyTextContPPT as Slide)
    }

    // 有文字和图片的正文
    if (texts.length > 0 && medias.length > 0 && tables.length === 0 && latex.length === 0) {
      // 先将 uls 和 ols 合并到 texts 中
      if (uls.length > 0) {
        uls.forEach((ul) => {
          texts.push(ul)
        })
      }
      if (ols.length > 0) {
        ols.forEach((ol) => {
          texts.push(ol)
        })
      }
      // 单图+段落
      if (medias.length === 1) {
        const singleImgSingleTxtContPPT = await GetTxtAdnImgContCourseware(tempId, {group, img: medias[0], txt: texts.join('')})
        pptData.push(singleImgSingleTxtContPPT as Slide)
      }
      else {
        if (medias.length === 2) {
          const twoImgAndTxtContPPT = await GetTwoImgAndTxtContCourseware(tempId, {group, img: medias, txt: texts})
          pptData.push(twoImgAndTxtContPPT as Slide)
        }
        else {
          const twoImgAndTxtContPPT = await GetThreeImgAndTxtContCourseware(tempId, {group, img: medias, txt: texts})
          pptData.push(twoImgAndTxtContPPT as Slide)
        }
      }
    }
  }

  // 加载PPT模板
  for (let i = 0;i < mdData.length; i++) {
    const item = mdData[i]

    if (item.type === 'title') {
      const title = await GetWelcomeCourseware(tempId, {title: item.name, author})
      pptData.push(title as Slide)
    }
    else if (item.type === 'section') {
      dirArr.push(item.name)
      const group = await GetGroupCourseware(tempId, item.name)
      pptData.push(group as Slide)
      await getContent(item.name, item.content)
    }
    else if (item.type === 'subsection') {
      const subGroup = await GetSubGroupCourseware(tempId, item.name, item.parent)
      pptData.push(subGroup as Slide)
      await getContent(item.name, item.content)
    }
    else if (item.type === 'paragraph') {
      await getContent(item.name, item.content)
    }
  }

  if (mdData.length > 1) {
    const dirPPT = await GetDirCourseware(tempId, dirArr) as Slide
    pptData.splice(1, 0, dirPPT)
  
    const endPPT = await GetEndCourseware(tempId) as Slide
    pptData.push(endPPT)
  }

  return pptData
}
